﻿//
// Copyright (c) 2011 Canyala Innovation AB
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 
// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
//

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace Canyala.Lagoon.Engineering
{
    /// <summary>
    /// Represents a unit prefix such as 'K' or 'M' or 'T'.
    /// </summary>
    public class Prefix
    {
        /// <summary>
        /// 
        /// </summary>
        public string Name { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        public string Token { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        public int PowerOfTen { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        public double Magnitude { get { return Math.Pow(10, PowerOfTen); } }

        /// <summary>
        /// 
        /// </summary>
        public static Prefix Empty = new Prefix(string.Empty, string.Empty, 0 );

        /// <summary>
        /// 
        /// </summary>
        /// <param name="quantity"></param>
        /// <returns></returns>
        public static Prefix FromQuantity(Quantity quantity)
        {
            Contract.Requires<ArgumentNullException>(quantity != null, "quantity");
            return quantity.Prefix;
        }

        public static Prefix FromName(string name)
        {
            if (prefixByName == null)
            {
                prefixByName = new Dictionary<string, Prefix>();
                foreach (Prefix p in prefixes) prefixByName.Add(p.Name, p);
            }

            return prefixByName[name];
        }

        public static Prefix FromToken(string token)
        {
            if (prefixByToken == null)
            {
                prefixByToken = new Dictionary<string, Prefix>();
                foreach (Prefix p in prefixes) prefixByToken.Add(p.Token, p);
            }

            return prefixByToken[token];
        }

        public static Prefix FromPower(int power)
        {
            if (prefixByPower == null)
            {
                prefixByPower = new Dictionary<int, Prefix>();

                foreach (Prefix p in prefixes)
                {
                    prefixByPower.Add(p.PowerOfTen, p);
                }
            }

            return prefixByPower[power];
        }

        public static Prefix FromText(string text)
        {
            #region Requires
            Contract.Requires<ArgumentNullException>(text != null, "text");
            Contract.Requires<ArgumentOutOfRangeException>(text.Length >= 2, "text.Length");
            #endregion

            Prefix prefix;
            if (prefixByToken.TryGetValue(text.Substring(0, 2), out prefix))
                return prefix;

            if (prefixByToken.TryGetValue(text.Substring(0, 1), out prefix))
                return prefix;

            return Prefix.Empty;
        }

        private Prefix(string name, string token, int powerOfTen)
        {
            Name = name;
            Token = token;
            PowerOfTen = powerOfTen;
        }

        private static Dictionary<string, Prefix> prefixByName;
        private static Dictionary<string, Prefix> prefixByToken;
        private static Dictionary<int, Prefix> prefixByPower;

        private static Prefix[] prefixes = new Prefix[]
        {
            new Prefix ( "yotta", "Y", 24 ),
            new Prefix ( "zetta", "Z", 21 ),
            new Prefix ( "exa", "E", 18 ),
            new Prefix ( "peta", "P", 15 ),
            new Prefix ( "tera", "T", 12 ),
            new Prefix ( "giga", "G", 9 ),
            new Prefix ( "mega", "M", 6 ),
            new Prefix ( "kilo", "k", 3 ),
            new Prefix ( "hekto", "h", 2 ),
            new Prefix ( "deca", "da", 1 ),
            Prefix.Empty,
            new Prefix ( "deci", "d", -1 ),
            new Prefix ( "centi", "c", -2 ),
            new Prefix ( "milli", "m", -3 ),
            new Prefix ( "micro", "µ", -6 ),
            new Prefix ( "nano", "n", -9),
            new Prefix ( "pico", "p", -12 ),
            new Prefix ( "femto", "f", -15 ),
            new Prefix ( "atto", "a", -18 ),
            new Prefix ( "zepto", "z", -21 ),
            new Prefix ( "yokto", "y", -24 )
        };
    }
}
